/*
 * PhotonRTOS础光实时操作系统 -- 自旋锁测试代码
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Lin Yang <s-yanglin@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include "../utest.h"

TEST(GetSpinlock)
{
	VAR(StatusType, AUTOMATIC) st;

#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00689] ⌈如果参数SpinlockID引用不存在的自旋锁，函数GetSpinlock应返回E_OS_ID 。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(AUTOSAR_NR_SPIN_LOCK);
	ASSERT_EQ(st, E_OS_ID);

	/**
	 * [SWS_Os_00690] ⌈ GetSpinlock函数应返回E_OS_INTERFERENCE_DEADLOCK如果 参数SpinlockID所指的自旋锁已被同一核心上的一个 TASK/ISR2 占用。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(0);
	ASSERT_EQ(st, E_OK);
	st = GetSpinlock(0);
	ASSERT_EQ(st, E_OS_INTERFERENCE_DEADLOCK);

	ReleaseSpinlock(0);

	/**
	 * [SWS_Os_00691] ⌈如果一个核上同时占用多个自旋锁的顺序不符合配置的顺序， GetSpinlock函数将返回E_OS_NESTING_DEADLOCK 。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(2);
	ASSERT_EQ(st, E_OK);
	st = GetSpinlock(1);
	ASSERT_EQ(st, E_OS_NESTING_DEADLOCK);

	ReleaseSpinlock(2);
	ReleaseSpinlock(1);


#endif

	/**
	 * [SWS_Os_00687] ⌈ GetSpinlock函数应该占用一个自旋锁。如果自旋锁已被占用，则该功能将忙于等待，直到自旋锁变得可用。 ⌋ ( SRS_Os_80021 )
	 */
	/* 执行会导致后续测试无法继续进行,如需测试,请解注释后单独测试 */
	/*
	 * autosar_init_smp_spin_lock();
	 * st = GetSpinlock(0);
	 * ASSERT_EQ(st, E_OK);
	 * pr_info("如果这是最后一句，则[SWS_Os_00687]测试通过，否则
	 * 测试不通过\n");
	 * autosar_spin_locks[0].owner_core_id++;
	 * st = GetSpinlock(0);
	 */

	/**
	 * [SWS_Os_00688] ⌈如果没有检测到错误， GetSpinlock函数应返回E_OK 。自旋锁现在被调用核心上的调用 TASK/ISR2 占用。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(0);
	ASSERT_EQ(st, E_OK);

	ReleaseSpinlock(0);

	/**
	 * [SWS_Os_00693] ⌈应允许在禁止中断的情况下调用GetSpinlock函数。 ⌋ ( SRS_Os_80021 )
	 */


	/**
	 * [SWS_Os_00694] ⌈ RESOURCE 被占用时，应允许调用GetSpinlock函数。 ⌋ ( SRS_Os_80021 )
	 */



}

TEST(ReleaseSpinlock)
{
	VAR(StatusType, AUTOMATIC) st;

#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00698] ⌈如果参数SpinlockID引用不存在的自旋锁，函数ReleaseSpinlock应返回E_OS_ID 。 ⌋ ( SRS_Os_80021 )
	 */
	st = ReleaseSpinlock(AUTOSAR_NR_SPIN_LOCK);
	ASSERT_EQ(st, E_OS_ID);

	/**
	 * [SWS_Os_00699] ⌈如果参数SpinlockID引用了未被调用 TASK 占用的自旋锁，函数ReleaseSpinlock应返回E_OS_STATE 。 ⌋ ( SRS_Os_80021 )
	 */
	st = ReleaseSpinlock(0);
	ASSERT_EQ(st, E_OS_STATE);


	/**
	 * [SWS_Os_00701] ⌈如果 TASK 试图释放自旋锁而另一个自旋锁（或资源）之前必须释放，则函数ReleaseSpinlock应返回E_OS_NOFUNC 。不应执行任何功能。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(0);
	ASSERT_EQ(st, E_OK);
	st = GetSpinlock(1);
	ASSERT_EQ(st, E_OK);
	st = ReleaseSpinlock(0);
	ASSERT_EQ(st, E_OS_NOFUNC);

	ReleaseSpinlock(1);
	ReleaseSpinlock(0);
#endif

	/**
	 * [SWS_Os_00696] ⌈ ReleaseSpinlock函数将释放已被相同（调用）TASK 占用的自旋锁。如果相关的GetSpinlock调用使用了配置的锁 (ECUC_Os_01038)，该函数还应执行已使用锁的撤消。 ⌋ ( SRS_Os_80021 )
	 */

	/**
	 * [SWS_Os_00697] ⌈如果未检测到错误， ReleaseSpinlock函数应返回E_OK 。自旋锁现在是空闲的，可以被相同的或其他的 TASK 占用。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(0);
	ASSERT_EQ(st, E_OK);
	st = ReleaseSpinlock(0);
	ASSERT_EQ(st, E_OK);
	st = GetSpinlock(0);
	ASSERT_EQ(st, E_OK);

	ReleaseSpinlock(0);
}

TEST(TryToGetSpinlock)
{
	VAR(StatusType, AUTOMATIC) st;
	VAR(TryToGetSpinlockType, AUTOMATIC) success;

#if defined(EXTENDED_STATUS)
	/**
	 * [SWS_Os_00706] ⌈如果函数TryToGetSpinlock不返回E_OK ，则 OUT 参数“ Success ”应未定义。 ⌋ ( SRS_Os_80021 )
	 */

	/**
	 * [SWS_Os_00707] ⌈如果参数SpinlockID引用不存在的自旋锁，函数TryToGetSpinlock应返回E_OS_ID 。 ⌋ ( SRS_Os_80021 )
	 */
	st = TryToGetSpinlock(AUTOSAR_NR_SPIN_LOCK, &success);
	ASSERT_EQ(st, E_OS_ID);

	/**
	 * [SWS_Os_00708] ⌈函数TryToGetSpinlock应返回E_OS_INTERFERENCE_DEADLOCK如果 参数SpinlockID所指的自旋锁已经被同一个核上的一个 TASK 占用。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(0);
	ASSERT_EQ(st, E_OK);
	st = TryToGetSpinlock(0, &success);
	ASSERT_EQ(st, E_OS_INTERFERENCE_DEADLOCK);

	ReleaseSpinlock(0);

	/**
	 * [SWS_Os_00709] ⌈如果 TASK 在持有不同的自旋锁的同时以可能导致死锁的方式试图占用自旋锁，则函数TryToGetSpinlock应返回E_OS_NESTING_DEADLOCK 。 ⌋ ( SRS_Os_80021 )
	 */
	st = GetSpinlock(1);
	ASSERT_EQ(st, E_OK);
	st = TryToGetSpinlock(0, &success);
	ASSERT_EQ(st, E_OS_NESTING_DEADLOCK);

	ReleaseSpinlock(1);
	ReleaseSpinlock(0);


#endif

	/**
	 * [SWS_Os_00705] ⌈如果自旋锁被成功占用，函数TryToGetSpinlock将设置 OUT 参数“ Success ”为TRYTOGETSPINLOCK_SUCCESS ，否则设置为TRYTOGETSPINLOCK_NOSUCCESS 。在这两种情况下都应返回E_OK 。 ⌋ ( SRS_Os_80021 )
	 * [SWS_Os_00704] ⌈ TryToGetSpinlock函数将自动测试自旋锁的
	 * 可用性，如果可用则占用它。返回成功的结果。 ⌋ (
	 *  SRS_Os_80021 )
	 */
	st = TryToGetSpinlock(0, &success);
	ASSERT_EQ(st, E_OK);
	ASSERT_EQ(success, TRYTOGETSPINLOCK_SUCCESS);
	autosar_spin_locks[0].owner_core_id++;
	st = TryToGetSpinlock(0, &success);
	ASSERT_EQ(st, E_OK);
	ASSERT_EQ(success, TRYTOGETSPINLOCK_NOSUCCESS);

	autosar_spin_locks[0].owner_core_id--;
	ReleaseSpinlock(0);

	/**
	 * [SWS_Os_00711] ⌈应允许在禁止中断时调用函数TryToGetSpinlock 。 ⌋ ( SRS_Os_80021 )
	 */


	/**
	 * [SWS_Os_00712] ⌈ RESOURCE 被占用时，应允许调用函数TryToGetSpinlock 。 ⌋ ( SRS_Os_80021 )
	 */


}


TEST_SUIT(Spinlock)
{
	UTEST_CASE(GetSpinlock);
	UTEST_CASE(ReleaseSpinlock);
	UTEST_CASE(TryToGetSpinlock);
}

